#!/usr/bin/env julia
"""
Lightweight CI Performance Benchmarks for NSEMSolver.jl

This script runs a minimal set of performance tests suitable for CI/CD pipelines.
It focuses on:
- Fast execution (< 5 minutes total)
- Essential performance metrics
- Regression detection
- Pass/fail criteria for automated testing
"""

using NSEMSolver

"""
    ci_performance_test() -> Bool

Run lightweight performance tests suitable for CI environments.
Returns true if all tests pass, false otherwise.
"""
function ci_performance_test()
    println("🚀 NSEMSolver.jl CI Performance Tests")
    println("=" * 50)
    
    start_time = time()
    all_tests_passed = true
    
    # Define performance thresholds (in seconds)
    performance_thresholds = Dict(
        "small_problem" => 5.0,    # N=3, n_block=2 should complete in <5s
        "medium_problem" => 15.0,  # N=4, n_block=3 should complete in <15s
        "solver_comparison" => 10.0 # Backend comparison should complete in <10s
    )
    
    # Test 1: Small problem performance
    println("\\n📊 Test 1: Small Problem Performance")
    try
        small_config = NSOptions(
            N = 3,
            n_block = 2,
            nu = 0.01,
            tfinal = 0.2,  # Short simulation time for CI
            cfl = 0.4,
            tol = 1e-5,
            solver = :julia,
            verbose = false
        )
        
        test_start = time()
        result = solve_navier_stokes_2d(small_config)
        test_time = time() - test_start
        
        if result.converged && test_time < performance_thresholds["small_problem"]
            println("   ✅ PASS: Small problem completed in $(@sprintf("%.2f", test_time))s (threshold: $(performance_thresholds["small_problem"])s)")
        else
            println("   ❌ FAIL: Small problem took $(@sprintf("%.2f", test_time))s or failed to converge")
            all_tests_passed = false
        end
        
    catch e
        println("   ❌ FAIL: Small problem test crashed: $e")
        all_tests_passed = false
    end
    
    # Test 2: Medium problem performance
    println("\\n📊 Test 2: Medium Problem Performance")
    try
        medium_config = NSOptions(
            N = 4,
            n_block = 3,
            nu = 0.01,
            tfinal = 0.2,  # Short simulation time for CI
            cfl = 0.3,
            tol = 1e-5,
            solver = :julia,
            verbose = false
        )
        
        test_start = time()
        result = solve_navier_stokes_2d(medium_config)
        test_time = time() - test_start
        
        if result.converged && test_time < performance_thresholds["medium_problem"]
            println("   ✅ PASS: Medium problem completed in $(@sprintf("%.2f", test_time))s (threshold: $(performance_thresholds["medium_problem"])s)")
        else
            println("   ❌ FAIL: Medium problem took $(@sprintf("%.2f", test_time))s or failed to converge")
            all_tests_passed = false
        end
        
    catch e
        println("   ❌ FAIL: Medium problem test crashed: $e")
        all_tests_passed = false
    end
    
    # Test 3: Solver backend availability and basic performance
    println("\\n📊 Test 3: Solver Backend Performance")
    try
        base_config = NSOptions(
            N = 3,
            n_block = 2,
            nu = 0.01,
            tfinal = 0.1,  # Very short for backend comparison
            cfl = 0.4,
            tol = 1e-4,    # Relaxed tolerance for speed
            verbose = false
        )
        
        # Test Julia backend
        julia_start = time()
        julia_config = NSOptions(base_config; solver = :julia)
        julia_result = solve_navier_stokes_2d(julia_config)
        julia_time = time() - julia_start
        
        julia_passed = julia_result.converged && julia_time < performance_thresholds["solver_comparison"]
        
        if julia_passed
            println("   ✅ PASS: Julia backend completed in $(@sprintf("%.2f", julia_time))s")
        else
            println("   ❌ FAIL: Julia backend took $(@sprintf("%.2f", julia_time))s or failed")
            all_tests_passed = false
        end
        
        # Test PETSc backend if available
        if HAS_PETSC
            try
                petsc_start = time()
                petsc_config = NSOptions(base_config; solver = :petsc)
                petsc_result = solve_navier_stokes_2d(petsc_config)
                petsc_time = time() - petsc_start
                
                if petsc_result.converged && petsc_time < performance_thresholds["solver_comparison"]
                    println("   ✅ PASS: PETSc backend completed in $(@sprintf("%.2f", petsc_time))s")
                else
                    println("   ⚠️  WARN: PETSc backend slow or failed ($(@sprintf("%.2f", petsc_time))s)")
                end
            catch e
                println("   ⚠️  WARN: PETSc backend test failed: $e")
            end
        else
            println("   ℹ️  INFO: PETSc backend not available")
        end
        
        # Test GCR backend if available
        if HAS_GCR
            try
                gcr_start = time()
                gcr_config = NSOptions(base_config; solver = :gcr)
                gcr_result = solve_navier_stokes_2d(gcr_config)
                gcr_time = time() - gcr_start
                
                if gcr_result.converged && gcr_time < performance_thresholds["solver_comparison"]
                    println("   ✅ PASS: GCR backend completed in $(@sprintf("%.2f", gcr_time))s")
                else
                    println("   ⚠️  WARN: GCR backend slow or failed ($(@sprintf("%.2f", gcr_time))s)")
                end
            catch e
                println("   ⚠️  WARN: GCR backend test failed: $e")
            end
        else
            println("   ℹ️  INFO: GCR backend not available")
        end
        
    catch e
        println("   ❌ FAIL: Solver backend test crashed: $e")
        all_tests_passed = false
    end
    
    # Test 4: Memory usage check
    println("\\n📊 Test 4: Memory Usage Check")
    try
        # Force garbage collection before measurement
        GC.gc()
        initial_memory = Base.gc_bytes()
        
        # Run a problem and measure memory growth
        memory_test_config = NSOptions(
            N = 4,
            n_block = 2,
            nu = 0.01,
            tfinal = 0.1,
            cfl = 0.4,
            tol = 1e-4,
            solver = :julia,
            verbose = false
        )
        
        result = solve_navier_stokes_2d(memory_test_config)
        
        GC.gc()
        final_memory = Base.gc_bytes()
        memory_used = final_memory - initial_memory
        memory_mb = memory_used / (1024 * 1024)
        
        # Memory threshold: should use less than 500MB for this small problem
        memory_threshold = 500.0
        
        if memory_mb < memory_threshold && result.converged
            println("   ✅ PASS: Memory usage $(@sprintf("%.1f", memory_mb)) MB (threshold: $(memory_threshold) MB)")
        else
            println("   ❌ FAIL: Excessive memory usage $(@sprintf("%.1f", memory_mb)) MB or convergence failure")
            all_tests_passed = false
        end
        
    catch e
        println("   ❌ FAIL: Memory test crashed: $e")
        all_tests_passed = false
    end
    
    # Summary
    total_time = time() - start_time
    println("\\n" * "=" * 50)
    println("📋 CI Performance Test Summary")
    println("=" * 50)
    println("Total test time: $(@sprintf("%.2f", total_time)) seconds")
    
    if all_tests_passed
        println("🎉 ALL TESTS PASSED")
        println("   Performance meets CI requirements")
        println("   No significant regressions detected")
        return true
    else
        println("❌ SOME TESTS FAILED")
        println("   Performance issues detected")
        println("   Check individual test results above")
        return false
    end
end

"""
    memory_stress_test() -> Bool

Run a memory stress test to ensure the solver doesn't leak memory or crash.
"""
function memory_stress_test()
    println("\\n🧠 Memory Stress Test")
    println("=" * 30)
    
    try
        # Run multiple sequential solves to check for memory leaks
        initial_memory = Base.gc_bytes()
        
        stress_config = NSOptions(
            N = 3,
            n_block = 2,
            nu = 0.01,
            tfinal = 0.05,  # Very short runs
            cfl = 0.5,
            tol = 1e-4,
            solver = :julia,
            verbose = false
        )
        
        n_runs = 5
        for i in 1:n_runs
            result = solve_navier_stokes_2d(stress_config)
            if !result.converged
                println("   ❌ FAIL: Run $i failed to converge")
                return false
            end
            
            # Force garbage collection between runs
            GC.gc()
            
            # Check memory growth
            current_memory = Base.gc_bytes()
            memory_growth = (current_memory - initial_memory) / (1024 * 1024)
            
            println("   Run $i: Memory growth $(@sprintf("%.1f", memory_growth)) MB")
            
            # If memory grows by more than 100MB per run, likely a leak
            if memory_growth > 100 * i
                println("   ⚠️  WARNING: Potential memory leak detected")
            end
        end
        
        final_memory = Base.gc_bytes()
        total_growth = (final_memory - initial_memory) / (1024 * 1024)
        
        if total_growth < 200  # Less than 200MB total growth acceptable
            println("   ✅ PASS: Memory stress test completed")
            println("   Total memory growth: $(@sprintf("%.1f", total_growth)) MB")
            return true
        else
            println("   ❌ FAIL: Excessive memory growth: $(@sprintf("%.1f", total_growth)) MB")
            return false
        end
        
    catch e
        println("   ❌ FAIL: Memory stress test crashed: $e")
        return false
    end
end

"""
    main()

Main entry point for CI performance tests.
"""
function main()
    println("NSEMSolver.jl Continuous Integration Performance Tests")
    println("Started: $(now())")
    println()
    
    # System information
    println("🖥️  System Information:")
    println("   Julia: $(VERSION)")
    println("   OS: $(Sys.KERNEL)")
    println("   CPU Cores: $(Sys.CPU_THREADS)")
    println("   Memory: $(@sprintf("%.1f", Sys.total_memory() / 1024^3)) GB")
    println("   Julia Threads: $(Threads.nthreads())")
    
    # Backend availability
    println("\\n⚙️  Available Backends:")
    println("   Julia: ✅")
    println("   PETSc: $(HAS_PETSC ? "✅" : "❌")")
    println("   GCR: $(HAS_GCR ? "✅" : "❌")")
    println("   MPI: $(HAS_MPI ? "✅" : "❌")")
    
    # Run main performance tests
    performance_passed = ci_performance_test()
    
    # Run memory stress test
    memory_passed = memory_stress_test()
    
    # Final result
    overall_passed = performance_passed && memory_passed
    
    println("\\n" * "=" * 60)
    println("🏁 FINAL CI TEST RESULT")
    println("=" * 60)
    
    if overall_passed
        println("🎉 CI PERFORMANCE TESTS PASSED")
        println("   ✅ Performance requirements met")
        println("   ✅ Memory usage acceptable")
        println("   ✅ No regressions detected")
        return 0
    else
        println("❌ CI PERFORMANCE TESTS FAILED")
        println("   $(performance_passed ? "✅" : "❌") Performance tests")
        println("   $(memory_passed ? "✅" : "❌") Memory tests")
        println("   🔄 Consider investigating performance issues")
        return 1
    end
end

# Run tests if script is executed directly
if abspath(PROGRAM_FILE) == @__FILE__
    exit(main())
end